home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 4 / FM Towns Free Software Collection 4 - Disc 1.iso / t_os / whisper / source / bplus.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-19  |  50.3 KB  |  2,034 lines

  1. /**************************************************************************
  2.  
  3.     FMR version Makeing by ken 89.9.5
  4.  
  5. ***************************************************************************/
  6. #include <stdio.h>
  7. #include <time.h>
  8. #include <string.h>
  9. #include <fmc.h>
  10.  
  11. #define unlink    remove
  12.  
  13. typedef long TIME_T;
  14.  
  15. extern int port,bps;
  16. extern void    Send_Failure();
  17.  
  18. TIME_T gtime(rt)
  19. long   *rt;
  20. {
  21.     long      l;
  22.  
  23.     l = clock() / CLK_TCK;
  24.     if ( rt != NULL )
  25.     *rt = l;
  26.     return l;
  27. }
  28. int    Async_BuffeR_Check( chx )
  29. unsigned char *chx;
  30. {
  31.     int     data,len;
  32.     unsigned int status;
  33.  
  34.     RSB_read(port,&len);
  35.     if ( len != 0 ) {
  36.     RSB_receive(port,&data,&status);
  37.     *chx = data;
  38.     }
  39.     return len;
  40. }
  41. void   Async_Send(chx)
  42. int    chx;
  43. {
  44.     unsigned int status;
  45.  
  46.     RSB_send(port,chx,&status);
  47. }
  48.  
  49. #define STMsg        0
  50. #define STFile       1
  51. #define STUpDow      2
  52. #define STType       3
  53. #define STComSent    4
  54. #define STDataSent   5
  55. #define STErrSent    6
  56. #define STPacSent    7
  57. #define STComRate    8
  58. #define STDataRate   9
  59. #define STElapsed    10
  60.  
  61. #define STComRead    20
  62. #define STDataRead   21
  63. #define STErrRead    22
  64. #define STPacRead    23
  65. #define STUplSize    24
  66. #define STDowSize    25
  67. #define STUplRem     26
  68. #define STDowRem     27
  69. #define STRemTime    28
  70.  
  71. /***********************************************************************/
  72. /****
  73.     BPLUS.INC - B Plus Protocol Support routines
  74.       (derived from BPROTO.INC)
  75.  
  76.     Copyright 1987, CompuServe Incorporated
  77.  
  78.     These routines may be used as-is or in modified form in any
  79.     personal computer terminal program to implement support of the
  80.     CompuServe B and B Plus Protocols for the purpose of transfering
  81.     information between CompuServe hosts and a personal computer.
  82.  
  83.     No warranty, expressed or implied, covers this code, or the specifications
  84.     of the B and B Plus Protocols.
  85.  
  86.  
  87.   Last update:
  88.        Russ Ranshaw      16-Dec-87   Corrected Upload Abort problems.
  89.        Russ Ranshaw      07-Apr-88   Corrected additional Abort problems.
  90.        Russ Ranshaw      09-Apr-88   Added Quote Set to + Packet.
  91.        Russ Ranshaw      10-Apr-88   Added Download Resume.
  92.        Russ Ranshaw      22-Apr-88   Added File Information to Download.
  93.                                      (File length only.)
  94.        Russ Ranshaw      11-May-88   Added check to control Upload degradation
  95.                                      under Send Ahead.
  96.        Russ Ranshaw      16-May-88   Remove debugging code for release
  97.                                      of Version 2.1
  98.        Russ Ranshaw      01-Jun-88   Added externally settable file size for
  99.                                      Downloads.  Use ST_Yes_or_No instead of
  100.                                      ST_Prompt to get Y/N response.
  101.        Russ Ranshaw      07-Jun-88   Added defensive check to see if Aborting
  102.                                      is already true.  Changed comm. rate
  103.                                      calculation.
  104.        Russ Ranshaw      23-Jun-88   Add check for <DLE><B> in ReSync.
  105.        Russ Ranshaw      04-Aug-88   Added WACK intercept to update the
  106.  
  107.                                      status display, mostly so that resumes
  108.                                      show some activity while the host calculates
  109.                                      it's CRC value.
  110.     Paul Resch     28-Aug-88   Converted to standard C code.
  111. ****/
  112.  
  113. /****************
  114. **
  115. **  This module implements the B-Protocol Functions.
  116. **
  117. **
  118. **  If you have any questions, contact:
  119. **      Russ Ranshaw, CompuServe Incorporated
  120. **         [70000,1010]
  121. **
  122. **  This source was originally derived from BP.C, written by
  123. **  Steve Wilhite, CompuServe Incorporated.
  124. **
  125. *****************/
  126.  
  127. /*
  128. const
  129.   UnitVersion = "2.2c";
  130.   UnitVerDate = "04 Aug 88";
  131.   UnitUpdBy   = "RWR";
  132. */
  133.  
  134. /****************************************************************************/
  135. /*
  136.  * C implementation notes:
  137.  *    Routines with names beginning "ST_" are not supplied.  They are
  138.  *        strictly console I/O.  Implement as needed, or see the PASCAL
  139.  *        version.
  140.  *    "Async_Send" is an extern that is passed a byte for output to the
  141.  *        serial port.
  142.  *    "Async_BuffeR_Read" is an extern that is passed the address of a byte.
  143.  *        If TRUE is returned, the byte will be from the serial port.
  144.  *        If FALSE is returned, the byte value is undefined.
  145.  *    The CRC subroutines are included in this module.
  146.  *
  147.  *    I have tried to keep as close as possible to Mr. Ranshaw's structure.
  148.  *    Please see the PASCAL source to clarify any confusion.
  149.  */
  150. /****************************************************************************/
  151.  
  152. #ifdef  DEBUG
  153. #define    STATIC
  154. #else
  155. #define    STATIC    static
  156. #endif
  157.  
  158. #define    TRUE    1
  159. #define    FALSE    0
  160.  
  161. STATIC    TIME_T    e_timer;
  162.  
  163. typedef char  maxstr[256];
  164.  
  165. int     BP_Auto_Resume = FALSE;  /* True to automatically attempt transfer */
  166.                                  /* resumption if the Initiator can do it  */
  167. int    BP_Use_File_Size = FALSE;
  168. long    BP_File_Size=0;
  169. /* BP_Quote_This is invoked to set bits in BP_Special_Quote_Set. */
  170. /* It must be called prior to calling BP_DLE_Seen for each character in the */
  171. /* ranges 0x00 -> 0x1f and 0x80 -> 0x9f that is to be quoted. */
  172. /*    BP_Quote_This (int Value); */
  173.  
  174. /* BP_Term_ENQ is invoked when Terminal Mode receives <ENQ> from host */
  175. /*    BP_Term_ENQ(); */
  176.  
  177. /* BP_Term_ESC_I is invoked when Terminal Mode receives <ESC><I> from host */
  178. /*    BP_Term_ESC_I (maxstr ESC_I_Response); */
  179.  
  180. /* BP_DLE_Seen is invoked when Terminal Mode receives <DLE> from host */
  181. /*    BP_DLE_Seen(); */
  182.  
  183. /*===========================================================================*/
  184.  
  185. typedef unsigned char QS_Array[8];
  186. typedef unsigned char QS_Array_p;
  187.  
  188. #define    bps300        0
  189. #define    bps600        1
  190. #define    bps1200        2
  191. #define    bps2400        3
  192. #define    bps4800        4
  193. #define    bps9600        5
  194. int    PortBps = bps2400;
  195.  
  196. STATIC    int    seq_num;       /* Current Sequence Number - init by Term_ENQ */
  197. STATIC    unsigned short    checksum;          /* May hold CRC */
  198.  
  199.          /* Initiator's Parameters */
  200. STATIC  unsigned char   His_WS,                      /* Initiator's Window Send     */
  201.   His_WR,                      /* Initiator's Window Receive  */
  202.   His_BS,                      /* Initiator's Block Size      */
  203.   His_CM;               /* Initiator's Check Method    */
  204. STATIC    QS_Array    His_QS;           /* Initiator's Quote Set */
  205.          /* The next 3 Parameters are for the B Plus File Transfer Application */
  206. STATIC    unsigned char His_DR=0, /* Initiator's Download Recovery Option */
  207.   His_UR=0,                     /* Initiator's Upload Recovery Option */
  208.   His_FI=0;                   /* Initiator's File Information Option */
  209.  
  210.          /* Negotiated Parameters */
  211. STATIC    unsigned char  Our_WS=0,    /* Negotiated Window Send   */
  212.   Our_WR=0,            /* Negotiated Window Receive */
  213.   Our_BS=0,            /* Negotiated Block Size     */
  214.   Our_CM=0;            /* Negotiated Check Method   */
  215. STATIC    QS_Array    Our_QS;    /* Our Quote Set */
  216. STATIC    unsigned char Our_DR=0,    /* Our Download Recovery Option */
  217.   Our_UR=0,            /* Our Upload Recovery Option */
  218.   Our_FI=0,            /* Our File Information Option */
  219.   Def_DR=0,            /* User's preferred DOW Resume option */
  220.   Def_BS=0;                       /* Default Block Size: varies depending */
  221.                     /* on the baud in use */
  222. STATIC unsigned char Port_Update_Rate=0;
  223.     /* Number of port bytes between Status */
  224.                                /* upldates for the Port     */
  225. STATIC    int    B_Plus=0;       /* True if B Plus in effect  */
  226. STATIC    int    Use_CRC=0;       /* True if CRC in effect     */
  227. STATIC    int    BP_Special_Quoting = 0;/* True to use BP_Special_Quote_Set */
  228. STATIC    QS_Array BP_Special_Quote_Set =  /* User's specified Quote Set */
  229.          {0x14, 0x00, 0xd4, 0x00,   /* ETX ENQ DLE XON XOFF NAK */
  230.           0x00, 0x00, 0x00, 0x00
  231.          };
  232.  
  233. STATIC    int    Buffer_Size=0;       /* Our_BS * 4                */
  234. STATIC    int    SA_Max=0;   /* 1 if SA not enabled, else Max_SA */
  235. STATIC    int    SA_Error_Count=0;   /* # of times S_Send_Data called */
  236.  
  237. STATIC    unsigned char    Quote_Table[256];   /* The quoting table */
  238.  
  239. STATIC    QS_Array  DQ_Full =
  240.           {0xff, 0xff, 0xff, 0xff,
  241.        0xff, 0xff, 0xff, 0xff
  242.           };
  243. STATIC    QS_Array  DQ_Default =
  244.         {0x14, 0x00, 0xd4, 0x00,    /* ETX ENQ DLE XON XOFF NAK */
  245.          0x00, 0x00, 0x00, 0x00
  246.         };
  247. STATIC    QS_Array  DQ_Minimal =
  248.         {0x14, 0x00, 0xd4, 0x00,    /* ETX ENQ DLE XON XOFF NAK */
  249.          0x00, 0x00, 0x00, 0x00
  250.         };
  251. STATIC    QS_Array  DQ_Extended =
  252.        {0x14, 0x00, 0xd4, 0x00,     /* ETX ENQ DLE XON XOFF NAK */
  253.         0x00, 0x00, 0x50, 0x00      /* XON XOFF */
  254.        };
  255.  
  256. #define   Max_Buf_Size   1032        /* Largest data block we can handle */
  257. #define   Max_SA  2                  /* Maximum number of waiting Packets */
  258.  
  259. #define   Def_Buf_Size   511         /* Default data block               */
  260. #define   Def_WS         1           /* I can send 2 Packets ahead       */
  261. #define   Def_WR         1           /* I can receive single send-ahead  */
  262. #define   Def_CM         1           /* I can handle CRC                 */
  263. #define   Def_DQ         1           /* I can handle non-quoted NUL      */
  264.                                        /* (including the `Tf' Packet       */
  265. #define   Def_UR         0           /* I can NOT handle Upload Recovery */
  266. #define   Def_FI         1           /* I can handle File Information */
  267.  
  268. #define   max_Errors     10
  269.  
  270.  
  271. /* Receive States */
  272.  
  273. #define   R_Get_DLE       0
  274. #define   R_Get_B         1
  275. #define   R_Get_Seq       2
  276. #define   R_Get_Data      3
  277. #define   R_Get_Check     4
  278. #define   R_Send_ACK      5
  279. #define   R_Timed_Out     6
  280. #define   R_Success       7
  281.  
  282. /* Send States */
  283.  
  284. #define   S_Get_DLE       1
  285. #define   S_Get_Num       2
  286. #define   S_Have_ACK      3
  287. #define   S_Get_Packet    4
  288. #define   S_Skip_Packet   5
  289. #define   S_Timed_Out     6
  290. #define   S_Send_NAK      7
  291. #define   S_Send_ENQ      8
  292. #define   S_Send_Data     9
  293.  
  294. /* Other Constants */
  295.  
  296. #define   dle   16
  297. #define   etx   03
  298. #define   nak   21
  299. #define   enq   05
  300.  
  301. typedef char    lstr[256];
  302. typedef struct {
  303.     int    seq;    /* Packet's sequence number  */
  304.     int    num;    /* Number of bytes in Packet */
  305.     unsigned char    buf[Max_Buf_Size]; /* Actual Packet data        */
  306.     } buf_type;
  307.  
  308. /****************************************************************************/
  309. void    ltoa( n, s )
  310. register long    n;
  311. register char    *s;
  312. {
  313.     register char    *t;
  314.     register long    i;
  315.     register char    c;
  316.     long    sign;
  317.     long    divten;
  318.  
  319.     if( (sign = n) < 0 )
  320.         n = -n;
  321.     t = s;
  322.     do
  323.     {
  324.         i = (divten = (n / 10)) * 10;    /* get ones digit (sigh) */
  325.  
  326.         *t++ = ( n - i ) + '0';
  327.     } while( (n = divten) > 0 );
  328.     if( sign < 0 )
  329.         *t++ = '-';
  330.     *t-- = '\0';
  331.     while( s < t )
  332.     {
  333.         c = *t;
  334.         *t-- = *s;
  335.         *s++ = c;
  336.     }
  337. }
  338. /****************************************************************************/
  339. /*
  340.   Clear_Quote_Table:
  341.     Initialize Quote_Table to all zeros (nothing quoted).
  342. */
  343.  
  344. STATIC void Clear_Quote_Table()
  345. {
  346.     int    i;
  347.  
  348.  
  349.     for( i = 0; i<=255; i++ )
  350.         Quote_Table [i] = 0;
  351. }
  352.  
  353. /*
  354.   Update_Quote_Table:
  355.     Sets the i-th entry of Quote_Table to the necessary quoting character
  356.     according to the i-th bit of the supplied Quote Set.
  357. */
  358.  
  359. STATIC void Update_Quote_Table (Quote_Set)
  360. QS_Array_p *Quote_Set;
  361. {
  362.     int    i, j, k;
  363.     unsigned char    b, c;
  364.  
  365.     k = 0;
  366.     c = 0x40;
  367.  
  368.     for( i = 0; i<=7; i++ )
  369.     {
  370.         if( i == 4 )
  371.                     /* Switch to upper control set */
  372.         {
  373.             c = 0x60;
  374.             k = 128;
  375.         }
  376.  
  377.         b = Quote_Set [i];
  378.  
  379.         for (j = 0; j<=7; j++ )
  380.         {
  381.             if ((b & 0x80) != 0)
  382.                 Quote_Table [k] = c;
  383.  
  384.             b = b << 1;
  385.             c = c + 1;
  386.             k = k + 1;
  387.         }
  388.     }
  389. }
  390.  
  391. /* BP_Quote_This sets bits in BP_Special_Quote_Set.                 */
  392. /* It sets BP_Special_Quoting true to use the special quote set.    */
  393. /* If Value = -1, the Special Quote Set is restored to its default. */
  394.  
  395. void    BP_Quote_This (Value)
  396. int    Value;
  397. {
  398.     int    i, j;
  399.  
  400.     if ((Value >= 0x00 && Value <= 0x1F) ||
  401.         (Value >= 0x80 && Value <= 0x9f) )
  402.     {
  403.         if (Value > 0x1f)
  404.         {
  405.             i = 4;
  406.             Value = Value & 0x1f;
  407.         }
  408.         else
  409.             i = 0;
  410.  
  411.         i = i + Value / 8;       /* = index into BP_Special_Quote_Set */
  412.         j = Value % 8;           /* = Bit number in the i-th byte */
  413.         BP_Special_Quote_Set [i] =
  414.             BP_Special_Quote_Set [i] || (0x80 >> j);
  415.         BP_Special_Quoting = TRUE;
  416.     }
  417.     else if (Value == -1)              /* Restore the Quote Set? */
  418.     {
  419.         for( i=0; i<sizeof(DQ_Minimal); i++ )
  420.             BP_Special_Quote_Set[i] = DQ_Minimal[i];
  421.         BP_Special_Quoting = FALSE;
  422.     }
  423. }
  424.  
  425. /*
  426.   BP_Term_ENQ is called when the terminal emulator receives the character <ENQ>
  427.   from the host.  Its purpose is to initialize for B Protocol and tell the
  428.   host that we support B Plus.
  429. */
  430.  
  431.  
  432. void    BP_Term_ENQ()
  433. {
  434.     int i;
  435.  
  436.     seq_num = 0;
  437.     Buffer_Size = 512;               /* Set up defaults */
  438.     Our_WS = 0;
  439.     Our_WR = 0;
  440.     Our_BS = 4;
  441.     Our_CM = 0;
  442.     Our_DR = 0;
  443.     Our_UR = 0;
  444.     Our_FI = 0;
  445.  
  446.     B_Plus      = FALSE;             /* Not B Plus Protocol */
  447.     Use_CRC     = FALSE;             /* Not CRC_16      */
  448.     SA_Max      = 1;                 /* Single Packet send */
  449.     SA_Error_Count = 0;              /* No Upload errors yet */
  450.  
  451.   /* Set up Our prefered Quoting Mask */
  452.     for( i=0; i<sizeof(DQ_Minimal); i++ )
  453.         Our_QS[i] = DQ_Minimal[i];
  454.  
  455.     Clear_Quote_Table();
  456.     Update_Quote_Table (Our_QS);
  457.  
  458.     Async_Send (dle);
  459.     Async_Send ('+');
  460.     Async_Send ('+');
  461.     Async_Send (dle);
  462.     Async_Send ('0');
  463. }
  464.  
  465. /*
  466.   BP_Term_ESC_I is called when <ESC><I> is received by the terminal emulator.
  467.   Note that CompuServe now recognizes the string ",+xxxx" as the final field.
  468.   THis provides a checksum (xxxx being the ASCII decimal representation of the
  469.   sum of all characters in the response string from # to +.  The purpose of
  470.   the checksum is to eliminate the need for retransmission and comparison of
  471.   the response.
  472. */
  473.  
  474.  
  475. void    BP_Term_ESC_I (esc_I_Response)
  476. char    esc_I_Response[];
  477. {
  478.     int    i;
  479.     maxstr    t;
  480.     int    cks;    /* checksum */
  481.  
  482.     cks = 0;
  483.  
  484.     for (i = 0; i<strlen (esc_I_Response); i++ )
  485.     {
  486.         Async_Send (esc_I_Response [i]);
  487.         cks += esc_I_Response [i];
  488.     }
  489.  
  490.     Async_Send (',');
  491.     Async_Send ('+');
  492.     cks = cks + ',' + '+';
  493.  
  494.     ltoa( (long)cks, t );
  495.  
  496.     i = 4 - strlen( t );    /* zero-fill */
  497.     while( i-- )
  498.         Async_Send( '0' );
  499.  
  500.     for (i = 0; i<strlen (t); i++ )
  501.         Async_Send (t [i]);
  502.  
  503.     Async_Send (0x0d);    /* <CR> */
  504. }
  505.  
  506.  
  507. /*
  508.   BP_DLE_Seen is called from the main program when the character <DLE> is
  509.   received from the host.
  510.  
  511.   This routine calls Read_Packet and dispatches to the appropriate
  512.   handler for the incoming Packet.
  513. */
  514.  
  515.  
  516. STATIC    int    ttime=0,
  517.     R_Size=0,           /* size of receiver buffer */
  518.     ch=0;               /* current character */
  519.  
  520. STATIC    int    xoff_flag=0,
  521.     Timed_Out=0,            /* we timed out before receiving character */
  522.     Packet_Received=0,      /* True if a Packet was received */
  523.     masked=0;               /* true if ctrl character was quoted */
  524.  
  525. STATIC    buf_type    SA_Buf[Max_SA+1];  /* Send-ahead buffers */
  526.  
  527. STATIC    int    SA_Next_to_ACK=0;    /* Which SA_Buf is waiting for an ACK */
  528. STATIC    int    SA_Next_to_Fill=0;   /* Which SA_Buf is ready for new data */
  529. STATIC    int    SA_Waiting=0;        /* Number of SA_Buf's waiting for ACK */
  530. STATIC    int    Aborting=0;          /* True if aborting the transfer ]*/
  531.  
  532. STATIC    unsigned char    R_buffer[Max_Buf_Size];
  533. STATIC    lstr    filename=0;                   /* pathname */
  534. STATIC    int        S_Counter=0;                  /* Used to pace status update */
  535. STATIC    int        R_Counter=0;
  536. STATIC    long    S_Com_Data=0;                 /* Comm Port Data traffic */
  537. STATIC    long    R_Com_Data=0;
  538. STATIC    long    S_File_Data=0;                /* File Data Traffic */
  539. STATIC  long    R_File_Data=0;
  540. STATIC    long    S_Packet_Count=0;             /* Packet count */
  541. STATIC    long    R_Packet_Count=0;
  542. STATIC    long    S_Error_Count=0;               /* Error count */
  543. STATIC    long    R_Error_Count=0;
  544. STATIC    long    S_File_Size=0;         /* Length of file already sent */
  545. STATIC    long    R_File_Size=0;         /* Length of file already received */
  546. STATIC    long    S_Remaining=0;         /* # bytes remaining to be sent */
  547. STATIC    long    R_Remaining=0;         /* # bytes reamining to be received */
  548. STATIC    long    Com_Rate=0;            /* Comm. bytes per second */
  549. STATIC    long    Data_Rate=0;           /* Effective Data bytes per second */
  550. STATIC    long    Time_Estimate=0;       /* Estimated time until completion */
  551. STATIC    int    Resume_Flag=0;         /* TRUE if attempting a DOW resume */
  552.  
  553. /***************************************************************************/
  554. /*
  555.  * crc
  556.  *
  557.  * Calculates XMODEM-style CRC (uses the CCITT V.41 polynomial but
  558.  * completely backwards from the normal bit ordering).
  559.  */
  560.  
  561.  
  562. STATIC    unsigned    crc_table[] = {
  563.         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
  564.         0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
  565.         0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
  566.         0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
  567.         0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
  568.         0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
  569.         0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
  570.         0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
  571.  
  572.         0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
  573.         0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
  574.         0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
  575.         0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
  576.         0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
  577.     0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
  578.         0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
  579.         0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
  580.         0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
  581.         0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
  582.         0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
  583.         0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
  584.         0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
  585.         0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  586.         0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
  587.         0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
  588.         0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
  589.         0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
  590.         0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
  591.         0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
  592.         0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
  593.         0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
  594.         0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
  595.         0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
  596.     };
  597.  
  598. STATIC    unsigned int    crc_16;
  599.  
  600. /*
  601.  * Init_CRC initializes for XMODEM style CRC calculation by setting
  602.  * crc_16 to value.  Typically value is 0 for XMODEM and -1 for
  603.  * B+ Protocl.  It returns the initial value.
  604.  */
  605. STATIC    int    Init_CRC (value)
  606. int    value;
  607. {
  608.     return( crc_16 = value );
  609. }
  610.  
  611. /*
  612.   Upd_CRC updates crc_16 and returns the updated value. */
  613.  
  614. STATIC    unsigned int    Upd_CRC (value)
  615. unsigned int    value;
  616. {
  617.     crc_16 = crc_table [((crc_16 >> 8) ^ (value)) & 0xff] ^ (crc_16 << 8);
  618.     return( crc_16 );
  619. }
  620. /***************************************************************************/
  621.  
  622. STATIC    void do_checksum (c)
  623. int    c;
  624. {
  625.     if (B_Plus && Use_CRC)
  626.         checksum = Upd_CRC ((unsigned short)c);
  627.     else
  628.     {
  629.         checksum = checksum << 1;
  630.  
  631.         if (checksum > 255)
  632.             checksum = (checksum & 0xff) + 1;
  633.  
  634.         checksum += c;
  635.  
  636.         if (checksum > 255)
  637.             checksum = (checksum & 0xff) + 1;
  638.     }
  639. }
  640.  
  641. STATIC    void send_byte (ch)
  642. unsigned char    ch;
  643. {
  644.     Async_Send (ch);
  645.     S_Com_Data++;
  646.     S_Counter++;
  647.     S_Counter = S_Counter % Port_Update_Rate;
  648.  
  649.     if (S_Counter == 0)
  650.         ST_Display_Value (STComSent, S_Com_Data);
  651. }
  652.  
  653. STATIC void send_masked_byte (ch)
  654. int    ch;
  655. {
  656.     ch &= 0xff;
  657.  
  658.     if (Quote_Table [ch] != 0)
  659.     {
  660.         send_byte (dle);
  661.         send_byte (Quote_Table [ch]);
  662.     }
  663.     else
  664.         send_byte (ch);
  665. }
  666.  
  667. STATIC void Send_ACK()
  668. {
  669.     send_byte (dle);
  670.     send_byte (seq_num + '0');
  671. }
  672.  
  673. STATIC void Send_NAK()
  674. {
  675.     send_byte (nak);
  676. }
  677.  
  678. /***********************
  679. STATIC void Send_ENQ()
  680. {
  681.     send_byte (enq);
  682. }
  683. ***********************/
  684.  
  685. STATIC int read_byte()
  686. {
  687.     unsigned char    chx;
  688.     unsigned short    Hiber;
  689.     TIME_T    start;
  690.  
  691.     Timed_Out = FALSE;
  692.     start = gtime(NULL);
  693.  
  694.     if ( !Aborting )
  695.         Hiber = 30;
  696.     else
  697.         Hiber = 10;
  698.  
  699.     while ( !Async_BuffeR_Check( &chx ) )
  700.     {
  701.  
  702.         if (gtime(NULL) - start >= Hiber)
  703.         {
  704.             Timed_Out = TRUE;
  705.             return( FALSE );
  706.         }
  707.     }
  708.  
  709.     ch = chx;
  710.     R_Com_Data++;
  711.     R_Counter++;
  712.     R_Counter = R_Counter % Port_Update_Rate;
  713.  
  714.     if (R_Counter == 0 )
  715.         ST_Display_Value (STComRead, R_Com_Data);
  716.  
  717.     return(TRUE);
  718. }
  719.  
  720.  
  721. STATIC int read_masked_byte()
  722. {
  723.     masked = FALSE;
  724.  
  725.     if (read_byte() == FALSE)
  726.         return(FALSE);
  727.  
  728.     if (ch == dle)
  729.     {
  730.         if (read_byte() == FALSE)
  731.             return(FALSE);
  732.  
  733.         if (ch < 0x60)
  734.             ch = ch & 0x1f;
  735.         else
  736.             ch = (ch & 0x1f) | 0x80;
  737.  
  738.         masked = TRUE;
  739.     }
  740.  
  741.     return(TRUE);
  742. }
  743.  
  744. /*
  745.   Increment Sequence Number
  746. */
  747.  
  748. STATIC    int    Incr_Seq (value)
  749. int    value;
  750. {
  751.     if (value == 9)
  752.         return( 0);
  753.     else
  754.         return(value + 1);
  755. }
  756.  
  757.  
  758. STATIC    int    Read_Packet (Lead_in_Seen, From_Send_Packet)
  759. int    Lead_in_Seen;
  760. int    From_Send_Packet;
  761. /*   Lead_in_Seen is true if the <DLE><B> has been seen already.  */
  762.  
  763.  
  764. /*   From_Send_Packet is true if called from Send_Packet          */
  765. /*        (causes exit on first error detected)                   */
  766.  
  767. /*   Returns True if Packet is available from host. */
  768.  
  769. {
  770.     short  State,
  771.         next_seq,
  772.         block_num,
  773.         errors,
  774.         new_cks;
  775.     int    i;
  776.     int    NAK_Sent;
  777.  
  778.     if (Packet_Received)      /* See if a Packet was picked up on a call to */
  779.                       /* Get_ACK */
  780.     {
  781.         Packet_Received = FALSE;
  782.         return( TRUE);
  783.     }
  784.  
  785.     NAK_Sent = FALSE;
  786.  
  787.     for( i=0; i<Buffer_Size; i++ )
  788.         R_buffer[i] = 0;
  789.  
  790.     next_seq = (seq_num +  1) % 10;
  791.     errors = 0;
  792.  
  793.     if (Lead_in_Seen)           /* Start off on the correct foot */
  794.         State = R_Get_Seq;
  795.     else State = R_Get_DLE;
  796.  
  797.     while( TRUE )
  798.     {
  799.         ttime = 300;
  800.  
  801.         switch  (State) {
  802.  
  803.         case R_Get_DLE :
  804.             if (ST_Check_Abort() && !Aborting)
  805.             {
  806.                 ST_Display_String (STMsg, "Aborting download per your request");
  807.                 Send_Failure ("AAborted by user");
  808.                 return(FALSE);
  809.             }
  810.  
  811.             if ( !read_byte() )
  812.                 State = R_Timed_Out;
  813.             else if ((ch & 0x7F) == dle )
  814.                 State = R_Get_B;
  815.             else if ((ch & 0x7F) == enq )
  816.                 State = R_Send_ACK;
  817.             break;
  818.  
  819.         case R_Get_B :
  820.             if (!read_byte())
  821.                 State = R_Timed_Out;
  822.             else if ((ch & 0x7F) == 'B')
  823.                 State = R_Get_Seq;
  824.             else if (ch == enq)
  825.                 State = R_Send_ACK;
  826.             else if (ch == ';')
  827.             {
  828.                 ST_Display_Value (STComRead, R_Com_Data);
  829.                 State = R_Get_DLE;
  830.             }
  831.             else State = R_Get_DLE;
  832.             break;
  833.  
  834.         case R_Get_Seq :
  835.             if( Resume_Flag )   /* Improve status display for DOW resume */
  836.             {
  837.                 e_timer = gtime(NULL);
  838.                 R_Com_Data = 2;
  839.             }
  840.             if (!read_byte())
  841.                 State = R_Timed_Out;
  842.             else if (ch == enq)
  843.                 State = R_Send_ACK;
  844.             else
  845.             {
  846.                 if (B_Plus && Use_CRC)
  847.                     checksum = Init_CRC (0xffff);
  848.                 else checksum = 0;
  849.  
  850.                 block_num = ch - '0';
  851.  
  852.                 do_checksum (ch);
  853.  
  854.                 i = 0;
  855.                 State = R_Get_Data;
  856.             }
  857.             break;
  858.  
  859.         case R_Get_Data :
  860.             if (!read_masked_byte())
  861.                 State = R_Timed_Out;
  862.             else if ((ch == etx) && !masked)
  863.             {
  864.  
  865.                 do_checksum (etx);
  866.                 State = R_Get_Check;
  867.             }
  868.             else
  869.             {
  870.                 R_buffer[i] = ch;
  871.                 i = i + 1;
  872.                 do_checksum (ch);
  873.             }
  874.             break;
  875.  
  876.         case R_Get_Check :
  877.             if (!read_masked_byte())
  878.                 State = R_Timed_Out;
  879.             else
  880.             {
  881.                 if (B_Plus && Use_CRC)
  882.                 {
  883.                     checksum = Upd_CRC ((unsigned int)ch);
  884.  
  885.                     if (!read_masked_byte())
  886.                         new_cks = checksum ^ 0xff;
  887.                     else
  888.                     {
  889.                         checksum =
  890.                             Upd_CRC((unsigned int)ch);
  891.                         new_cks = 0;
  892.                     }
  893.                 }
  894.                 else new_cks = ch;
  895.  
  896.                 if (new_cks != checksum)
  897.                     State = R_Timed_Out;
  898.                 else if (R_buffer[0] == 'F') /* Watch for Failure Packet */
  899.                     State = R_Success; /* which is accepted regardless */
  900.                 else if (block_num == seq_num) /* Watch for duplicate block */
  901.                     State = R_Send_ACK; /* Simply ACK it */
  902.                 else if (block_num != next_seq)
  903.                     State = R_Timed_Out; /* Bad seq num */
  904.                 else State = R_Success;
  905.             }
  906.             break;
  907.  
  908.         case R_Timed_Out :
  909.             errors++;
  910.  
  911.             if ((errors > max_Errors) || (From_Send_Packet))
  912.                 return( FALSE );
  913.  
  914.             if (!NAK_Sent || !B_Plus)
  915.             {
  916.                 R_Error_Count++;
  917.                 ST_Display_Value (STErrRead, R_Error_Count);
  918.                 NAK_Sent = TRUE;
  919.                 Send_NAK();
  920.             }
  921.  
  922.             State = R_Get_DLE;
  923.             break;
  924.  
  925.         case R_Send_ACK :
  926.  
  927.             if (!Aborting)
  928.                 Send_ACK();
  929.  
  930.             State = R_Get_DLE;        /* wait for the next block */
  931.             break;
  932.  
  933.         case R_Success :
  934.             ST_Display_Value (STComRead, R_Com_Data);
  935.             ST_Display_Value (STComSent, S_Com_Data);
  936.  
  937.             if (!Aborting)
  938.                 seq_num = block_num;
  939.  
  940.             R_Size = i;
  941.             R_Packet_Count++;
  942.             ST_Display_Value (STPacRead, R_Packet_Count);
  943.             return(TRUE);
  944.  
  945.         }
  946.     }
  947.  
  948. } /* Read_Packet */
  949.  
  950. STATIC    void Send_Data (BuffeR_Number)
  951. int    BuffeR_Number;
  952. {
  953.     int    i;
  954.     buf_type    *p;
  955.  
  956.     p = &SA_Buf [BuffeR_Number];
  957.  
  958.     if (B_Plus && Use_CRC)
  959.         checksum = Init_CRC (0xffff);
  960.     else checksum = 0;
  961.  
  962.     send_byte (dle);
  963.     send_byte ('B');
  964.  
  965.     send_byte (p->seq + '0');
  966.     do_checksum (p->seq + '0');
  967.  
  968.     for (i = 0; i<=p->num; i++ )
  969.     {
  970.         send_masked_byte (p->buf [i]);
  971.         do_checksum (p->buf[i]);
  972.     }
  973.  
  974.     send_byte (etx);
  975.     do_checksum (etx);
  976.  
  977.      if (B_Plus && Use_CRC)
  978.         send_masked_byte (checksum >> 8);
  979.  
  980.     send_masked_byte (checksum);
  981.  
  982. }
  983.  
  984. STATIC    int    Incr_SA (Old_Value)
  985. int    Old_Value;
  986. {
  987.     if (Old_Value == Max_SA)
  988.         return(0);
  989.     else
  990.         return(Old_Value + 1);
  991. }
  992.  
  993. /*
  994.   ReSync is called to restablish syncronism with the remote.  This is
  995.   accomplished by sending <ENQ><ENQ> and waiting for the sequence
  996.   <DLE><d><DLE><d> to be received, ignoring everything else.
  997.  
  998.   Return is -1 on time out, `B` if <DLE><B> seen, else the digit <d>.
  999. */
  1000.  
  1001. STATIC    int    ReSync()
  1002. #define      Get_First_DLE     1
  1003. #define      Get_First_Digit   2
  1004. #define      Get_Second_DLE    3
  1005. #define      Get_Second_Digit  4
  1006. {
  1007.     int    State,
  1008.     Digit_1;
  1009.  
  1010.     send_byte (enq);     /* Send <ENQ><ENQ> */
  1011.     send_byte (enq);
  1012.     State = Get_First_DLE;
  1013.  
  1014.     while(1)
  1015.     {
  1016.         switch (State) {
  1017.         case Get_First_DLE :
  1018.             if (!read_byte())
  1019.                 return(-1);
  1020.  
  1021.             if (ch == dle)
  1022.                 State = Get_First_Digit;
  1023.             break;
  1024.  
  1025.         case Get_First_Digit :
  1026.             if (!read_byte())
  1027.                 return(-1);
  1028.  
  1029.             if ((ch >= '0') && (ch <= '9'))
  1030.             {
  1031.                 Digit_1 = ch;
  1032.                 State = Get_Second_DLE;
  1033.             }
  1034.             else if (ch == 'B')
  1035.                 return( ch );
  1036.             break;
  1037.  
  1038.         case Get_Second_DLE :
  1039.             if (!read_byte())
  1040.                 return(-1);
  1041.  
  1042.             if (ch == dle)
  1043.                 State = Get_Second_Digit;
  1044.             break;
  1045.  
  1046.         case Get_Second_Digit :
  1047.             if (!read_byte())
  1048.                 return(-1);
  1049.  
  1050.             if ((ch >= '0') && (ch <= '9'))
  1051.             {
  1052.                 if (Digit_1 == ch  )
  1053.                     return(ch);
  1054.                 else if (ch == 'B')
  1055.                     return( ch );
  1056.                 else
  1057.                 {
  1058.                     Digit_1 = ch;
  1059.                     State = Get_Second_DLE;
  1060.                 }
  1061.             }
  1062.             else State = Get_Second_DLE;
  1063.             break;
  1064.  
  1065.         } /* case */
  1066.     }  /* while TRUE */
  1067. }
  1068.  
  1069. /*
  1070.   Get_ACK is called to wait until the SA_Buf indicated by SA_Next_to_ACK
  1071.   has been ACKed by the host.
  1072. */
  1073.  
  1074. STATIC    int    Get_ACK()
  1075. {
  1076.     int    State,
  1077.         errors,
  1078.         block_num,
  1079.         i;
  1080. /*  int    new_cks;*/
  1081.     int    Sent_ENQ;
  1082.     int    SA_Index;
  1083.  
  1084.     Packet_Received = FALSE;
  1085.     errors = 0;
  1086.     Sent_ENQ = FALSE;
  1087.     State = S_Get_DLE;
  1088.  
  1089.     while(1)
  1090.     {
  1091.     switch (State) {
  1092.     case S_Get_DLE :
  1093.         ttime = 300;
  1094.  
  1095.         if (ST_Check_Abort() && !Aborting)
  1096.         {
  1097.             ST_Display_String (STMsg,
  1098.                 "Aborting the upload per your request");
  1099.             Send_Failure ("AAborted by user");
  1100.             return(FALSE);
  1101.         }
  1102.  
  1103.         if (!read_byte()  )
  1104.             State = S_Timed_Out;
  1105.         else
  1106.         {
  1107.             if (ch == dle)
  1108.                 State = S_Get_Num;
  1109.             else if (ch == nak )
  1110.                 State = S_Send_ENQ;
  1111.             else if (ch == etx )
  1112.                 State = S_Send_NAK;
  1113.         }
  1114.         break;
  1115.  
  1116.     case S_Get_Num :
  1117.         if (!read_byte() )
  1118.             State = S_Timed_Out;
  1119.         else if ((ch >= '0') && (ch <= '9'))
  1120.             State = S_Have_ACK;           /* Received ACK */
  1121.         else if (ch == 'B' )
  1122.         {
  1123.             if (!Aborting)
  1124.                 State = S_Get_Packet; /* Try to receive a Packet */
  1125.             else State = S_Skip_Packet;   /* Try to skip a Packet */
  1126.         }
  1127.         else if (ch == nak)
  1128.             State = S_Send_ENQ;
  1129.         else if (ch == ';')
  1130.         {    /* Received a WACK (Wait Acknowledge) */
  1131.             ST_Display_Value (STComRead, R_Com_Data);
  1132.             State = S_Get_DLE;
  1133.         }
  1134.         else State = S_Timed_Out;
  1135.         break;
  1136.  
  1137.     case S_Get_Packet :
  1138.         if (Read_Packet (TRUE, TRUE) )
  1139.         {
  1140.             Packet_Received = TRUE;
  1141.  
  1142.             if (R_buffer [0] == 'F')  /* Check for Failure Packet */
  1143.             {
  1144.                 Send_ACK();
  1145.                 return(FALSE);
  1146.             }
  1147.  
  1148.             State = S_Get_DLE;     /* Stay here to find the ACK */
  1149.         }
  1150.         else State = S_Get_DLE;         /* Receive failed; keep watching for ACK */
  1151.         break;
  1152.  
  1153.     case S_Skip_Packet :    /* Skip an incoming Packet */
  1154.         if (!read_byte())
  1155.             State = S_Timed_Out;
  1156.         else if (ch == etx )
  1157.         {                  /* Get the Checksum or CRC */
  1158.             if (!read_masked_byte())
  1159.                 State = S_Timed_Out;
  1160.             else if (!Use_CRC)
  1161.                 State = S_Get_DLE;
  1162.             else if (!read_masked_byte())
  1163.                 State = S_Timed_Out;
  1164.             else State = S_Get_DLE;
  1165.         }
  1166.         break;
  1167.  
  1168.     case S_Have_ACK :
  1169.         block_num = ch - '0';
  1170.         ST_Display_Value (STComSent, S_Com_Data);
  1171.         ST_Display_Value (STComRead, R_Com_Data);
  1172.  
  1173.         if (SA_Buf [SA_Next_to_ACK].seq == block_num  )
  1174.         {                  /* This is the one we're waiting for */
  1175.             SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
  1176.             SA_Waiting = SA_Waiting - 1;
  1177.  
  1178.             if (SA_Error_Count > 0 )     /* Apply heuristic to control */
  1179.             SA_Error_Count--; /* Upload Performance degradation */
  1180.  
  1181.             return(TRUE);
  1182.         }
  1183.         else if ((SA_Buf [Incr_SA (SA_Next_to_ACK)].seq == block_num) &&
  1184.             SA_Waiting == 2)
  1185.         {                 /* Must have missed an ACK */
  1186.             SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
  1187.             SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
  1188.             SA_Waiting = SA_Waiting - 2;
  1189.  
  1190.             if (SA_Error_Count > 0)
  1191.                 SA_Error_Count--;
  1192.  
  1193.             return(TRUE);
  1194.         }
  1195.         else if (SA_Buf [SA_Next_to_ACK].seq == Incr_Seq (block_num) )
  1196.         {
  1197.             if (Sent_ENQ)
  1198.                 State = S_Send_Data; /* Remote missed first block */
  1199.             else State = S_Get_DLE;       /* Duplicate ACK */
  1200.         }
  1201.         else
  1202.         {
  1203.             if (!Aborting)        /* While aborting, ignore any */
  1204.                 State = S_Timed_Out; /* ACKs that have been sent   */
  1205.             else State = S_Get_DLE;       /* which are not for the failure */
  1206.         }                                   /* Packet. */
  1207.  
  1208.         Sent_ENQ = FALSE;
  1209.         break;
  1210.  
  1211.     case S_Timed_Out :
  1212.         State = S_Send_ENQ;
  1213.         break;
  1214.  
  1215.     case S_Send_NAK :
  1216.         errors++;
  1217.         S_Error_Count++;
  1218.         ST_Display_Value (STErrSent, S_Error_Count);
  1219.  
  1220.         if (errors > max_Errors)
  1221.             return(FALSE);
  1222.  
  1223.         Send_NAK();
  1224.  
  1225.         State = S_Get_DLE;
  1226.         break;
  1227.  
  1228.     case S_Send_ENQ :
  1229.         errors++;
  1230.         S_Error_Count++;
  1231.         ST_Display_Value (STErrSent, S_Error_Count);
  1232.  
  1233.         if ((errors > max_Errors) || (Aborting && (errors > 3)))
  1234.             return(FALSE);
  1235.  
  1236.         ch = ReSync();
  1237.         if (ch == -1)
  1238.             State = S_Get_DLE;
  1239.         else if (ch == 'B')
  1240.         {
  1241.             if( !Aborting )
  1242.                 State = S_Get_Packet;    /* Try to receive a Packet */
  1243.             else
  1244.                 State = S_Skip_Packet;    /* Try to skip a Packet */
  1245.         }
  1246.         else State = S_Have_ACK;
  1247.         Sent_ENQ   = TRUE;
  1248.         break;
  1249.  
  1250.     case S_Send_Data :
  1251.         SA_Error_Count += 3;
  1252.  
  1253.         if (SA_Error_Count >= 12) /* Stop Upload Send Ahead if too many */
  1254.         SA_Max = 1;           /* errors have occured */
  1255.  
  1256.         SA_Index = SA_Next_to_ACK;
  1257.  
  1258.         for (i = 1; i<=SA_Waiting; i++ )
  1259.         {
  1260.             Send_Data (SA_Index);
  1261.             SA_Index = Incr_SA (SA_Index);
  1262.         }
  1263.  
  1264.         State = S_Get_DLE;
  1265.         Sent_ENQ = FALSE;
  1266.         break;
  1267.     }
  1268.     }
  1269. } /* Get_ACK */
  1270.  
  1271. STATIC    int    send_Packet (size)
  1272. int    size;
  1273. {
  1274.     while (SA_Waiting >= SA_Max) /* Allow for possible drop out of Send Ahead */
  1275.     {
  1276.         if (!Get_ACK() )
  1277.             return(FALSE);
  1278.     }
  1279.  
  1280.     seq_num = Incr_Seq (seq_num);
  1281.     SA_Buf [SA_Next_to_Fill].seq = seq_num;
  1282.     SA_Buf [SA_Next_to_Fill].num = size;
  1283.     Send_Data (SA_Next_to_Fill);
  1284.     SA_Next_to_Fill = Incr_SA (SA_Next_to_Fill);
  1285.     SA_Waiting = SA_Waiting + 1;
  1286.     S_Packet_Count++;
  1287.     ST_Display_Value (STComSent, S_Com_Data);
  1288.     ST_Display_Value (STPacSent, S_Packet_Count);
  1289.     return(TRUE);
  1290. }
  1291.  
  1292. /*
  1293.   SA_Flush is called after sending the last Packet to get host's
  1294.   ACKs on outstanding Packets.
  1295. */
  1296.  
  1297. STATIC    int    SA_Flush()
  1298. {
  1299.     while (SA_Waiting > 0)
  1300.     {
  1301.         if (!Get_ACK())
  1302.             return(FALSE);
  1303.     }
  1304.     return( TRUE );
  1305. }
  1306.  
  1307. STATIC    void Send_Failure (Reason)
  1308. char    Reason[];
  1309. {
  1310.     int    i;
  1311.     buf_type    *p;
  1312.  
  1313.     SA_Next_to_ACK = 0;
  1314.     SA_Next_to_Fill = 0;
  1315.     SA_Waiting = 0;
  1316.     Aborting   = TRUE;          /* Inform Get_ACK we're aborting ]*/
  1317.  
  1318.     p = &SA_Buf [0];
  1319.     p->buf [0] = 'F';
  1320.     for (i = 1; i<=strlen(Reason); i++ )
  1321.         p->buf [i] = (Reason [i]);
  1322.  
  1323.     if ( send_Packet (strlen(Reason)) )
  1324.         SA_Flush();   /* Gotta wait for the Initiator to ACK it */
  1325. }
  1326.  
  1327. /* Send_File is called to send a file to the host */
  1328.  
  1329. STATIC    int    Send_File (name)
  1330. char    name[];
  1331. {
  1332.     int    n;
  1333.       FILE    *data_File;
  1334.     buf_type    *p;
  1335.  
  1336.     data_File = fopen (name,"rb");
  1337.  
  1338.     if (data_File == 0 )
  1339.     {
  1340.         ST_Display_String (STMsg, "Cannot find that file");
  1341.         Send_Failure ("MFile not found");
  1342.         return(FALSE);
  1343.     }
  1344.  
  1345.     fseek(data_File,0L,2);        /* seek to end of file */
  1346.     S_Remaining = ftell(data_File);    /* how long is this file ? */
  1347.     fseek(data_File,0L,0);        /* back to the start, ready to go */
  1348.     ST_Display_Value (STUplRem, S_Remaining);
  1349. /* Send_File_Information here ? */
  1350.  
  1351. /*----------------
  1352.     S_Com_Data = 0;
  1353.     R_Com_Data = 0;
  1354.     e_timer = gtime(NULL);
  1355. -------------------*/
  1356.     do
  1357.     {
  1358.         p = &SA_Buf [SA_Next_to_Fill];
  1359.             p->buf [0] = 'N';
  1360.             n = fread (&p->buf[1], 1, Buffer_Size, data_File);
  1361.  
  1362.         if (n > 0)
  1363.         {
  1364.             if (send_Packet (n) == FALSE)
  1365.             {
  1366.                 fclose(data_File);
  1367.                 return(FALSE);
  1368.             }
  1369.  
  1370.             S_File_Data = S_File_Data +  (n);
  1371.             S_File_Size = S_File_Size +  (n);
  1372.             S_Remaining = S_Remaining -  (n);
  1373.             ST_Display_Value (STUplSize, S_File_Size);
  1374.             ST_Display_Value (STDataSent, S_File_Data);
  1375.             ST_Display_Value (STUplRem, S_Remaining);
  1376.             Time_Estimate = gtime(NULL) - e_timer;
  1377.             ST_Display_Value (STElapsed, Time_Estimate);
  1378.  
  1379.             if (Time_Estimate != 0)
  1380.             {
  1381.                 Com_Rate = S_Com_Data / Time_Estimate;
  1382.                 Data_Rate = S_File_Data / Time_Estimate;
  1383.                 ST_Display_Value (STComRate, Com_Rate);
  1384.                 ST_Display_Value (STDataRate, Data_Rate);
  1385.  
  1386.                 if (Data_Rate != 0)
  1387.                 {
  1388.                     Time_Estimate = S_Remaining / Data_Rate;
  1389.                     ST_Display_Value (STRemTime, Time_Estimate);
  1390.                 }
  1391.             }
  1392.         }
  1393.     } while(n > 0);
  1394.  
  1395.     if (ferror(data_File) != 0)
  1396.     {
  1397.         Send_Failure ("EFile read failure");
  1398.         ST_Display_String (STMsg, "Read failure...aborting");
  1399.         fclose(data_File);
  1400.         return(FALSE);
  1401.     }
  1402.  
  1403. /* Inform host that the file was sent */
  1404.  
  1405.     p = &SA_Buf [SA_Next_to_Fill];
  1406.     p->buf [0] = 'T';
  1407.     p->buf [1] = 'C';
  1408.  
  1409.     if (send_Packet (2) == FALSE)
  1410.     {
  1411.         fclose (data_File);
  1412.         return(FALSE);
  1413.     }
  1414.     else
  1415.     {
  1416.         fclose (data_File);
  1417.         if (!SA_Flush())
  1418.             return(FALSE);
  1419.         return(TRUE);
  1420.     }
  1421.  
  1422. } /* Send_File */
  1423.  
  1424. /*
  1425.     Do_Transport_Parameters is called when a Packet type of + is received.
  1426.     It sends a Packet of Our local B Plus parameters and sets the Our_xx
  1427.     parameters to the minimum of the Initiator's and Our own parameters.
  1428. */
  1429.  
  1430. STATIC    void Do_Transport_Parameters()
  1431. {
  1432.     int    Quote_Set_Present;
  1433.     int    i;
  1434.     buf_type    *p;
  1435.  
  1436.     if (BP_Special_Quoting)
  1437.     {
  1438.         for( i=0; i<8; i++ )
  1439.             Our_QS[i] = BP_Special_Quote_Set[i];
  1440.     }
  1441.     else
  1442.     {
  1443.         for( i=0; i<8; i++ )
  1444.             Our_QS[i] = DQ_Minimal[i];
  1445.     }
  1446.  
  1447.     for (i = R_Size + 1; i<=512; i++ ) R_buffer [i] = 0;
  1448.  
  1449.     His_WS = R_buffer [1];     /* Pick out Initiator's parameters */
  1450.     His_WR = R_buffer [2];
  1451.     His_BS = R_buffer [3];
  1452.     His_CM = R_buffer [4];
  1453.  
  1454.     His_QS [0] = R_buffer [7];
  1455.     His_QS [1] = R_buffer [8];
  1456.     His_QS [2] = R_buffer [9];
  1457.     His_QS [3] = R_buffer [10];
  1458.     His_QS [4] = R_buffer [11];
  1459.     His_QS [5] = R_buffer [12];
  1460.     His_QS [6] = R_buffer [13];
  1461.     His_QS [7] = R_buffer [14];
  1462.  
  1463.     His_DR = R_buffer [15];
  1464.     His_UR = R_buffer [16];
  1465.     His_FI = R_buffer [17];
  1466.  
  1467.     if (R_Size >= 14)
  1468.         Quote_Set_Present = TRUE;
  1469.     else Quote_Set_Present = FALSE;
  1470.  
  1471.     p = &SA_Buf [SA_Next_to_Fill];
  1472.     p->buf [0] = '+';  /* Prepare to return Our own parameters */
  1473.     p->buf [1] = Def_WS;
  1474.     p->buf [2] = Def_WR;
  1475.     p->buf [3] = Def_BS;
  1476.     p->buf [4] = Def_CM;
  1477.     p->buf [5] = Def_DQ;
  1478.     p->buf [6] = 0;          /* No transport layer here */
  1479.  
  1480.     for (i = 0; i<=7; i++ )
  1481.         p->buf [i + 7] = Our_QS [i];
  1482.  
  1483.     if (BP_Auto_Resume)      /* Set Download Resume according to */
  1484.         Def_DR = 2;       /* user's preference */
  1485.     else Def_DR = 1;
  1486.  
  1487.     p->buf [15] = Def_DR;
  1488.     p->buf [16] = Def_UR;
  1489.     p->buf [17] = Def_FI;
  1490.  
  1491.     Update_Quote_Table (DQ_Full);   /* Send the + Packet w/ full quoting */
  1492.  
  1493.     if (!send_Packet (17) )
  1494.         return;
  1495.  
  1496.     if (SA_Flush())                 /* Wait for host's ACK on Our Packet */
  1497.     {
  1498.         if (His_WS < Def_WR)      /* Take minimal subset of Transport Params. */
  1499.             Our_WR = His_WS;   /* If he can send ahead, we can receive it. */
  1500.         else Our_WR = Def_WR;
  1501.  
  1502.         if (His_WR < Def_WS)      /* If he can receive send ahead, we can send it. */
  1503.             Our_WS = His_WR;
  1504.         else Our_WS = Def_WS;
  1505.  
  1506.  
  1507.         if( His_BS < Def_BS)
  1508.             Our_BS = His_BS;
  1509.         else Our_BS = Def_BS;
  1510.  
  1511.         if (His_CM < Def_CM)
  1512.             Our_CM = His_CM;
  1513.         else Our_CM = Def_CM;
  1514.  
  1515.         if (His_DR < Def_DR)
  1516.             Our_DR = His_DR;
  1517.         else Our_DR = Def_DR;
  1518.  
  1519.         if (His_UR < Def_UR)
  1520.             Our_UR = His_UR;
  1521.         else Our_UR = Def_UR;
  1522.  
  1523.         if (His_FI < Def_FI)
  1524.             Our_FI = His_FI;
  1525.         else Our_FI = Def_FI;
  1526.  
  1527.         if (Our_BS == 0)
  1528.             Our_BS = 4;    /* Default */
  1529.  
  1530.         Buffer_Size = Our_BS * 128;
  1531.  
  1532.         B_Plus = TRUE;
  1533.  
  1534.         if (Our_CM == 1)
  1535.             Use_CRC = TRUE;
  1536.  
  1537.         if (Our_WS != 0)
  1538.             SA_Max = Max_SA;
  1539.     }
  1540.  
  1541.     Clear_Quote_Table();            /* Restore Our Quoting Set */
  1542.     Update_Quote_Table (Our_QS);
  1543.  
  1544.     if (Quote_Set_Present)     /* Insert Initiator's Quote Set */
  1545.         Update_Quote_Table (His_QS);
  1546. }
  1547.  
  1548. /* Check_Keep is called from Receive_File when a fatal error */
  1549. /* occurs.  It asks the user if the file should be retained */
  1550.  
  1551. STATIC    void Check_Keep (data_File, Name)
  1552. FILE    *data_File;
  1553. char    Name[];
  1554. {
  1555.     char    yn;
  1556.     char    str[80];
  1557.  
  1558.     fclose (data_File);
  1559.  
  1560.     if ((!BP_Auto_Resume) || (!B_Plus) || (Our_DR == 0))
  1561.     {
  1562.         strcpy( str, "Do you wish to retain the partial " );
  1563.         strcat( str, Name );
  1564.         strcat( str, "?" );
  1565.         ST_Yes_or_No( str, &yn );
  1566.     }
  1567.     else
  1568.         yn = 'Y';
  1569.  
  1570.     if (yn == 'N')
  1571.     {
  1572.         unlink ( Name );
  1573.         ST_Display_String (STMsg, "File erased.");
  1574.     }
  1575.     else
  1576.     {
  1577. /* implementation dependent option: Hide the file from casual view */
  1578.         ST_Display_String (STMsg, "File retained.");
  1579.     }
  1580. }
  1581.  
  1582. /* Process_File_Information is called from Receive_File when a TI Packet */
  1583. /* is received.  It extracts the desired information from the Packet.    */
  1584.  
  1585. STATIC    char    Val_Str[50];
  1586. STATIC    int    e_i=0, e_j=0, e_n=0;
  1587.  
  1588. STATIC void Extract_String()   /* Extract next string of characters */
  1589. {
  1590.     int    Digit_Seen;
  1591.  
  1592.     Digit_Seen = FALSE;
  1593.     e_j = 0;
  1594.     while (e_i <= e_n)
  1595.     {
  1596.         if ((R_buffer [e_i] >= '0') && (R_buffer [e_i] <= '9') )
  1597.         {
  1598.             Digit_Seen = TRUE;
  1599.             e_j++;
  1600.             Val_Str [e_j] = R_buffer [e_i];
  1601.         }
  1602.         else if (Digit_Seen)
  1603.         {
  1604.             Val_Str [0] = e_j;
  1605.             return;
  1606.         }
  1607.  
  1608.         e_i++;
  1609.     }
  1610. }
  1611.  
  1612. STATIC    void Process_File_Information()
  1613. {
  1614.     int    i;
  1615.  
  1616.     e_n = R_Size - 1;
  1617.     e_i = 4;       /* Skip data type and compression flag */
  1618.     Extract_String();
  1619. /*    Val (Val_Str, R_Remaining, e_j); */
  1620.     R_Remaining = 0;
  1621.     for( i=1; i<=e_j; i++ )
  1622.         R_Remaining = (R_Remaining * 10) + (Val_Str[i] - '0');
  1623.     R_Remaining = R_Remaining - R_File_Size;  /* Adjust for Dow Resume */
  1624.     ST_Display_Value (STDowRem, R_Remaining);
  1625.  
  1626.   /* Ignore rest of parameters for now */
  1627.  
  1628.     S_Packet_Count = 0;
  1629.     R_Packet_Count = 0;
  1630. }
  1631.  
  1632. /* Receive_File is called to receive a file from the host */
  1633.  
  1634. STATIC    int    Receive_File (Name)
  1635. char    Name[];
  1636. {
  1637.     FILE    *Data_File;
  1638.     int    status;
  1639.     long    File_Length;      /* For download resumption */
  1640.     lstr    Work_String;
  1641.     int    Packet_Len;
  1642.     int    i, n;
  1643.     char    yn;
  1644.     char    Dow_Type;
  1645.     buf_type    *p;
  1646.  
  1647.     Dow_Type = 'D';         /* Assume normal downloading */
  1648.  
  1649.     Data_File = fopen( Name, "rwb" );    /* open for r/w first */
  1650.  
  1651.     if (Data_File != NULL)    /* this file already exists */
  1652.     {                   /* See if we can try automatic resume */
  1653.         if ((Our_DR > 1) && BP_Auto_Resume)
  1654.             Dow_Type = 'R';  /* Remote supports `Tf', let's try */
  1655.         else if ((Our_DR > 0))
  1656.         {
  1657.             ST_Display_String (STMsg, "File already exists.");
  1658.             ST_Yes_or_No ("Do you wish to resume downloading? ", &yn);
  1659.  
  1660.             if (yn == 'Y')
  1661.                 Dow_Type = 'R';
  1662.             else
  1663.                 ST_Display_String (STMsg, "File being overwritten.");
  1664.         }
  1665.     }
  1666.  
  1667.     switch( Dow_Type ) {
  1668.     case 'D':
  1669.         if( Data_File )
  1670.             fclose( Data_File );    /* close the read/write file */
  1671.         Data_File = fopen( Name, "wb" );    /* open for write */
  1672.         if (Data_File == NULL)
  1673.         {
  1674.             Send_Failure ("CCannot create file");
  1675.             return(FALSE);
  1676.         }
  1677.         Send_ACK();
  1678.         break;
  1679.  
  1680.     case 'R' :
  1681.                      /* Resume download */
  1682.         /* file is open and at start */
  1683.         ST_Display_String (STMsg, "Calculating CRC");
  1684.  
  1685.         p = &SA_Buf [SA_Next_to_Fill];
  1686.         if (Dow_Type == 'R')
  1687.         {
  1688.             checksum = Init_CRC (0xffff);
  1689.             do {
  1690.                 n = fread (&p->buf [0], 1, Buffer_Size,
  1691.                     Data_File);
  1692.                 for (i = 0; i<n; i++ )
  1693.                     checksum =
  1694.                         Upd_CRC((unsigned int)p->buf [i]);
  1695.                     } while( n > 0 );
  1696.         }
  1697.         else
  1698.             checksum = 0;
  1699.  
  1700.         p->buf [0] = 'T';
  1701.         p->buf [1] = 'r';
  1702.  
  1703.         Packet_Len = 2;
  1704.         File_Length = ftell(Data_File);
  1705.  
  1706.         ltoa (File_Length, Work_String);
  1707.         strcat( Work_String, " " );
  1708.  
  1709.         for (i = 0; i<strlen(Work_String); i++ )
  1710.         {
  1711.             p->buf [Packet_Len] = Work_String [i];
  1712.             Packet_Len++;
  1713.         }
  1714.  
  1715.         ltoa ((long)checksum, Work_String);
  1716.         strcat( Work_String, " " );
  1717.  
  1718.         for (i = 0; i<strlen(Work_String); i++ )
  1719.         {
  1720.             p->buf [Packet_Len] = Work_String [i];
  1721.             Packet_Len++;
  1722.         }
  1723.  
  1724.         if (!send_Packet (Packet_Len - 1)) /* Send_Data sends 0..Size */
  1725.         {
  1726.             fclose (Data_File);
  1727.             return(FALSE);
  1728.         }
  1729.  
  1730.         if (!SA_Flush())
  1731.         {
  1732.             fclose (Data_File);
  1733.             return(FALSE);
  1734.         }
  1735.  
  1736.         R_File_Size = File_Length;
  1737.         ST_Display_Value (STDowSize, R_File_Size);
  1738.         ST_Display_String (STMsg, "Host calculating CRC...");
  1739.         Resume_Flag = TRUE;
  1740.         break;
  1741.     }
  1742.  
  1743.  
  1744. /*
  1745.   Process each incoming Packet until 'TC' Packet received or failure
  1746. */
  1747.  
  1748.     R_Packet_Count = 0;
  1749.     S_Packet_Count = 0;
  1750.  
  1751.     if( BP_Use_File_Size )
  1752.         R_Remaining = BP_File_Size;
  1753.     else
  1754.         R_Remaining = 0;
  1755.   while(TRUE)
  1756.     {
  1757.       if (Read_Packet (FALSE, FALSE))
  1758.           {
  1759.             switch (R_buffer[0]) {
  1760.               case 'N' :
  1761.         if( Resume_Flag )
  1762.         {
  1763.             ST_Display_String( STMsg, "Resuming Download" );
  1764.             Resume_Flag = FALSE;
  1765.         }
  1766.  
  1767.         status = fwrite( &R_buffer[1], 1, R_Size - 1, Data_File );
  1768.  
  1769.                   if ((status != (R_Size - 1)))
  1770.                     {
  1771.                       ST_Display_String (STMsg, "Write failure...aborting");
  1772.                       Send_Failure ("EWrite failure");
  1773.                       Check_Keep (Data_File, Name);
  1774.                       return(FALSE);
  1775.                     }
  1776.                   R_File_Data = R_File_Data + (R_Size - 1);
  1777.           ST_Display_Value (STDataRead, R_File_Data);
  1778.                   R_File_Size = R_File_Size +  (status);
  1779.                   ST_Display_Value (STDowSize, R_File_Size);
  1780.  
  1781.                   Time_Estimate = gtime(NULL) - e_timer;
  1782.                   ST_Display_Value (STElapsed, Time_Estimate);
  1783.  
  1784.                   if (Time_Estimate != 0)
  1785.                     {
  1786.                       Com_Rate = R_Com_Data / Time_Estimate;
  1787.                       Data_Rate = R_File_Data / Time_Estimate;
  1788.                       ST_Display_Value (STComRate, Com_Rate);
  1789.                       ST_Display_Value (STDataRate, Data_Rate);
  1790.                     }
  1791.                   else Data_Rate = 0;
  1792.  
  1793.                   if (R_Remaining != 0)
  1794.                              /* Decrement remaining byte count */
  1795.                     {
  1796.                       R_Remaining = R_Remaining - (R_Size - 1);
  1797.                       ST_Display_Value (STDowRem, R_Remaining);
  1798.  
  1799.  
  1800.                       if (Data_Rate != 0)
  1801.                         {
  1802.                           Time_Estimate = R_Remaining / Data_Rate;
  1803.                           ST_Display_Value (STRemTime, Time_Estimate);
  1804.                         }
  1805.                     }
  1806.  
  1807.  
  1808.                   Send_ACK();
  1809.                 break;
  1810.  
  1811.               case 'T' :
  1812.                   if (R_buffer[1] == 'C')
  1813.                     {
  1814.                       ST_Display_String (STMsg, "*** Transfer Complete ***");
  1815.                       status = fclose (Data_File);
  1816.  
  1817.                       if (status == EOF)
  1818.                         {
  1819.                           ST_Display_String (STMsg, "Failure during close...aborting");
  1820.                           Send_Failure ("EError during close");
  1821.                           Check_Keep (Data_File, Name);
  1822.                           return(FALSE);
  1823.                         }
  1824.  
  1825.                       Send_ACK();
  1826.                       return(TRUE);
  1827.                     }
  1828.                 else if (R_buffer [1] == 'I')
  1829.                   {
  1830.                     Send_ACK();
  1831.                     Process_File_Information();
  1832.                   }
  1833.                 else if ((R_buffer [1] == 'f') && BP_Auto_Resume)
  1834.                               /* `Tf' Packet implies host failed the */
  1835.                   {          /* CRC check on a DOW resume */
  1836.             fclose (Data_File);       /* So...replace the file */
  1837.             Data_File = fopen(Name, "wb");
  1838.             if (Data_File == NULL)
  1839.             {
  1840.                 Send_Failure ("CCannot create file");
  1841.  
  1842.                 ST_Display_String (STMsg,
  1843.                     "CRC check failed; cannot create file");
  1844.                 return(FALSE);
  1845.             }
  1846.  
  1847.                     if (Our_FI != 0 || BP_Use_File_Size)
  1848.                       R_Remaining = R_Remaining + R_File_Size;
  1849.  
  1850.                     R_File_Size = 0;
  1851.                     ST_Display_String (STMsg, "CRC check failed; overwriting file");
  1852.             Resume_Flag = FALSE;
  1853.             e_timer = gtime(NULL);
  1854.             S_Com_Data = 0;
  1855.             R_Com_Data = 0;
  1856.                     Send_ACK();
  1857.                   }
  1858.                 else
  1859.                   {
  1860.                     ST_Display_String (STMsg, "Invalid termination Packet...aborting");
  1861.                     Send_Failure ("NInvalid T Packet");
  1862.                     Check_Keep (Data_File, Name);
  1863.                     return(FALSE);
  1864.                   }
  1865.               break;
  1866.  
  1867.               case 'F' :
  1868.                   Send_ACK();
  1869.                   ST_Display_String (STMsg, "Failure Packet received...aborting");
  1870.                   Check_Keep (Data_File, Name);
  1871.                   return(FALSE);
  1872.  
  1873.             }
  1874.  
  1875.           }
  1876.         else
  1877.           {
  1878.             if (!Aborting)
  1879.               ST_Display_String (STMsg, "Download failure");
  1880.             Check_Keep (Data_File, Name);
  1881.             return(FALSE);
  1882.           }
  1883.     }
  1884.  
  1885. } /* Receive_File */
  1886.  
  1887. /* =================================================================== */
  1888.  
  1889. void BP_DLE_Seen()
  1890. {   /* DLE_Seen */
  1891.  
  1892.     int    i;
  1893.  
  1894.   /*
  1895.     Begin by getting the next character.  If it is <B> then enter the
  1896.     B_Protocol state.  Otherwise simply return.
  1897.   */
  1898.  
  1899.   Port_Update_Rate = 30;
  1900. /*********************
  1901.   ST_Initialize(0);
  1902. **********************/
  1903.   if (!read_byte())
  1904.     return;
  1905.  
  1906.  
  1907.   if (ch != 'B')
  1908.     return;
  1909.  
  1910.   SA_Next_to_ACK  = 0;    /* Initialize Send-ahead variables */
  1911.   SA_Next_to_Fill = 0;
  1912.   SA_Waiting      = 0;
  1913.   Aborting        = FALSE;
  1914.   Packet_Received = FALSE;
  1915.  
  1916.   /* Establish Data Block Size as a function of the Baud */
  1917.   /* The intent is to keep the per-Packet time to 4-5 seconds */
  1918.  
  1919.   PortBps = bps;       /* Apend FMR version */
  1920.  
  1921.   switch (PortBps) {
  1922.     case bps300:
  1923.         Def_BS = 1;
  1924.         Port_Update_Rate = 30;
  1925.     break;
  1926.     case bps600:
  1927.     case bps1200:
  1928.         Def_BS = 4;
  1929.         Port_Update_Rate = 120;
  1930.     break;
  1931.     case bps2400:
  1932.     case bps4800:
  1933.     case bps9600:
  1934.         Def_BS = 8;
  1935.         Port_Update_Rate = 240;
  1936.     break;
  1937.     }
  1938.  
  1939.   /*  <DLE><B> received; begin B Protocol */
  1940.  
  1941.   xoff_flag   = TRUE;
  1942.  
  1943.   R_Counter   = 0;
  1944.   S_Counter   = 0;
  1945.   R_File_Data = 0;
  1946.   S_File_Data = 0;
  1947.   R_Com_Data  = 0;
  1948.   S_Com_Data  =  (0);
  1949.   S_Packet_Count =  (0);
  1950.   R_Packet_Count =  (0);
  1951.   S_File_Size =  (0);
  1952.   R_File_Size =  (0);
  1953.   S_Error_Count =  (0);
  1954.   R_Error_Count =  (0);
  1955.     Resume_Flag = FALSE;
  1956.  
  1957.   if (Read_Packet (TRUE, FALSE))
  1958.       {
  1959.         /* Dispatch on the type of Packet just received */
  1960.  
  1961.         switch (R_buffer[0]) {
  1962.           case 'T':                      /* File Transfer Application */
  1963.                 ST_Initialize(0);
  1964.         ST_Display_Value (STComRead, R_Com_Data);
  1965.         S_Com_Data = 0;
  1966.         R_Com_Data = 0;
  1967.         e_timer = gtime(NULL);
  1968.  
  1969.         switch (R_buffer[1]) {
  1970.                    case 'D' :
  1971.             ST_Display_String (STUpDow, "Downloading ");
  1972.             break;
  1973.                    case 'U' :
  1974.             ST_Display_String (STUpDow, "Uploading ");
  1975.             break;
  1976.                    default:
  1977.                        ST_Display_String (STMsg, "Unimplemented Transfer Function");
  1978.                        Send_Failure ("NUnimplemented Transfer function");
  1979.                        ST_Terminate();
  1980.                        return;
  1981.                  }
  1982.  
  1983.                  switch (R_buffer[2]) {
  1984.                    case 'A':
  1985.             ST_Display_String (STType, "ASCII");
  1986.             break;
  1987.                    case 'B':
  1988.             ST_Display_String (STType, "Binary");
  1989.             break;
  1990.                    default:
  1991.                        ST_Display_String (STMsg, "Unimplemented File Type");
  1992.                        Send_Failure ("NUnimplemented file type");
  1993.                        ST_Terminate();
  1994.                        return;
  1995.                  }
  1996.  
  1997.                  i = 2;
  1998.          filename[0] = '\0';
  1999.  
  2000.                  while ( R_buffer[i] != 0 ) {
  2001.             if ( i >= (R_Size - 1)) {
  2002.             filename[i - 2] = '\0';
  2003.             break;
  2004.             }
  2005.             i++;
  2006.             filename[i-3] = R_buffer[i];
  2007.                  }
  2008.  
  2009.          ST_Display_String (STFile, filename);
  2010.                  S_Packet_Count =  (0);
  2011.                  R_Packet_Count =  (0);
  2012.  
  2013.                  if (R_buffer[1] == 'U')
  2014.                    Send_File (filename);
  2015.                  else
  2016.                    Receive_File (filename);
  2017.  
  2018.                  ST_Terminate();
  2019.                break;
  2020.  
  2021.           case '+':          /* Received Transport Parameters Packet */
  2022.               Do_Transport_Parameters();
  2023.         break;
  2024.  
  2025.           default:
  2026.                    /* Unknown Packet; tell the host we don't know */
  2027.               Send_Failure ("NUnknown Packet Type");
  2028.         break;
  2029.  
  2030.         }  /* of case */
  2031.  
  2032.       }    /* of if Read_Packet then*/
  2033. } /* DLE_Seen */
  2034.